'use client';

import React, { useImperativeHandle, useMemo, useState } from 'react';
import clsx from 'clsx';
import toast from 'react-hot-toast';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { useForm, Controller } from 'react-hook-form';
import { Select } from 'src/components/Select';
import { useRequest } from 'ahooks';
import { getTagList } from 'src/actions/tag';
import { useAtomValue } from 'jotai';
import { storageSystemOptionsAtom } from 'src/model';

export interface Values {
  file: File;
  alt?: string;
  storageSystemId: string;
  isPublic?: boolean;
  tags?: string[];
}

export interface FormImageProps {
  className?: string;
  /**
   * 表单模式：新增(new) / 编辑(update)
   * @default 'new'
   */
  mode?: 'new' | 'update';
  ref?: React.Ref<ReturnType<typeof useForm<Values>>>;
  defaultValues?: Partial<Values>;
  onSubmit?: (data: Values) => void | Promise<void>;
}

const formSchema = z.object({
  file: z
    .instanceof(File, {
      message: '请上传文件',
    })
    .refine((file) => file.size < 50 * 1024 * 1024, {
      message: '文件大小不能超过 50MB',
    }),
  alt: z
    .string()
    .max(250, {
      message: '描述不能超过 250 个字符',
    })
    .optional(),
  storageSystemId: z
    .string({
      required_error: '文件存储系统为必填项',
    })
    .nonempty({
      message: '请选择文件存储系统',
    }),
  isPublic: z.boolean().optional(),
  tags: z.array(z.string()).optional(),
});

function FormImageNoMemoized(props: FormImageProps) {
  const { ref, className, mode = 'new', defaultValues, onSubmit } = props;

  // State
  const [loading, setLoading] = useState(false);
  const storageSystemOptions = useAtomValue(storageSystemOptionsAtom);

  // Requests
  const { data: tagList } = useRequest(getTagList);

  // Memoized
  const tagOptions = useMemo(
    () =>
      tagList?.map((tag) => ({
        label: tag.name,
        value: tag.id,
      })),
    [tagList]
  );

  // Form
  const form = useForm<Values>({
    defaultValues: {
      storageSystemId: storageSystemOptions[0]?.value,
      ...defaultValues,
    },
    resolver: zodResolver(formSchema),
  });

  const {
    register,
    control,
    handleSubmit,
    formState: { errors },
  } = form;

  useImperativeHandle(ref, () => form, [form]);

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault(); // 阻止默认提交行为，避免页面刷新
        const submit = handleSubmit((data) => {
          try {
            if (onSubmit) {
              setLoading(true);
              const cb = onSubmit(data);
              if (cb instanceof Promise) {
                cb.then(() => {
                  setLoading(false);
                }).catch((error) => {
                  setLoading(false);
                  toast.error((error as Error)?.message || '提交失败，请稍后重试');
                });
                return;
              }
              setLoading(false);
            }
          } catch (error) {
            setLoading(false);
            toast.error((error as Error)?.message || '提交失败，请稍后重试');
          }
        });
        submit(e);
      }}
    >
      <fieldset className={clsx('fieldset', className)}>
        {mode === 'new' && (
          <>
            <label className="label required-mark">图片</label>
            <Controller
              name="file"
              control={control}
              render={({ field: { onChange, value, ...rest } }) => (
                <>
                  <input
                    {...rest}
                    type="file"
                    onChange={(e) => {
                      // 当用户选择文件时处理，file value
                      if (e.target.files && e.target.files.length > 0) {
                        onChange(e.target.files[0]);
                      }
                    }}
                    className="w-full file-input file-input-bordered"
                    accept=".jpg,.jpeg,.png,.gif,.webp,.avif,.tiff,.svg"
                  />
                  <span className="inline-block truncate w-full label leading-none">
                    {value
                      ? `已选择：${value.name}；文件大小：${(value.size / 1024).toFixed(1)}KB`
                      : '请选择图片上传'}
                  </span>
                </>
              )}
            />
            <p className="h-3 text-xs text-error">{errors.file?.message}</p>
          </>
        )}

        <label className="label">描述</label>
        <textarea {...register('alt')} className="w-full textarea" placeholder="请填写图片描述" />
        <p className="h-3 text-xs text-error">{errors.alt?.message}</p>

        <label className="label required-mark">存储系统</label>
        <Controller
          name="storageSystemId"
          control={control}
          render={({ field }) => (
            <Select
              {...field}
              className="w-full"
              placeholder="请选择文件存储系统"
              options={storageSystemOptions}
            />
          )}
        />
        <p className="h-3 text-xs text-error">{errors.storageSystemId?.message}</p>

        <label className="label">是否公开（不公开无法通过公共链接访问）</label>
        <input {...register('isPublic')} type="checkbox" className="toggle" />
        <p className="h-3 text-xs text-error">{errors.isPublic?.message}</p>

        <label className="label">标签</label>
        <Controller
          name="tags"
          control={control}
          render={({ field }) => (
            <Select
              {...field}
              className="w-full"
              multiple
              placeholder="请选择标签"
              options={tagOptions}
            />
          )}
        />
        <p className="h-3 text-xs text-error">{errors.tags?.message}</p>
        <button type="submit" className="btn btn-primary mt-4" disabled={loading}>
          {loading && <span className="loading loading-spinner" />}
          {loading ? '提交中' : '提交'}
        </button>
      </fieldset>
    </form>
  );
}

export const FormImage = React.memo(FormImageNoMemoized);
